#1.作用域相关

#基于字典形式获取局部变量和全局变量
# 在理解这两个函数时，首先来理解一下 Python 中的名字空间概念。Python 使用叫做名字空间的东西来记录变量的轨迹。名字空间只是一个字典，它的键字就是变量名，字典的值就是那些变量的值。
# 实际上，名字空间可以像 Python 的字典一样进行访问。
# 每个函数都有着自已的名字空间，叫做局部名字空间，它记录了函数的变量，包括函数的参数和局部定义的变量。每个模块拥有它自已的名字空间，叫做全局名字空间，它记录了模块的变量，包括函数、类、其它导入的模块、模块级的变量和常量。还有就是内置名字空间，任何模块均可访问它，它存放着内置的函数和异常。
# 当一行代码要使用变量 x 的值时，Python 会到所有可用的名字空间去查找变量，按照如下顺序：
# 1、局部名字空间 - 特指当前函数或类的方法。如果函数定义了一个局部变量 x，Python将使用这个变量，然后停止搜索。
# 2、全局名字空间 - 特指当前的模块。如果模块定义了一个名为 x 的变量，函数或类，Python将使用这个变量然后停止搜索。
# 3、内置名字空间 - 对每个模块都是全局的。作为最后的尝试，Python 将假设 x 是内置函数或变量。
# 如果 Python 在这些名字空间找不到 x，它将放弃查找并引发一个 NameError 的异常，同时传递 There is no variable named 'x' 这样一条信息。
# from module import 和 import module 之间的不同。使用 import module，模块自身被导入，但是它保持着自已的名字空间，这就是为什么你需要使用模块名来访问它的函数或属性（module.function）的原因。但是使用 from module import，实际上是从另一个模块中将指定的函数和属性导入到你自己的名字空间，
# 这就是为什么你可以直接访问它们却不需要引用它们所来源的模块的原因。

# locals 是只读的，globals 不是。
# locals 不可修改，globals 可以修改，原因是：
# locals() 实际上没有返回局部名字空间，它返回的是一个拷贝。所以对它进行修改，修改的是拷贝，而对实际的局部名字空间中的变量值并无影响。
# globals() 返回的是实际的全局名字空间，而不是一个拷贝与 locals 的行为完全相反。
# 所以对 globals 所返回的 dictionary 的任何的改动都会直接影响到全局变量的取值。

# z = 7 #定义全局变量
# def foo0(arg):
#     x = 1
#     print(locals())
#     print('x=',x)
#     locals()['x'] = 2 #修改的是局部名字空间的拷贝，而实际的局部名字空间中的变量值并无影响。
#     print(locals())
#     print("x=",x)
#
# foo0(3)
# print(globals())
# print('z=',z)
# globals()["z"] = 8 #globals（）返回的是实际的全局名字空间，修改变量z的值
# print(globals())
# print("z=",z)

# 1.locals() -获取执行本方法所在命名空间内的局部变量的字典
# def foo(arg,a):
#     x = 1
#     y = 'xxxxxx'
#     for i in range(10):
#         j = 1
#         k = i
#     print(locals())
# foo(1,2)
# # 2.globals()-获取全局变量的字典

#2. 其他

#2.1 字符串类型代码的执行
#a. eval
# 以下是 eval() 方法的语法:
# eval(expression[, globals[, locals]])
# 参数
# expression -- 表达式。
# globals -- 变量作用域，全局命名空间，如果被提供，则必须是一个字典对象。
# locals -- 变量作用域，局部命名空间，如果被提供，可以是任何映射对象。
#示例：
# x = 7
# def hello():
#     print("hello world")
# print(eval('3*x'))
# print(eval('pow(2,2)'))
# eval('hello()')

#b. exec
#exec 执行储存在字符串或文件中的Python语句，相比于 eval，exec可以执行更复杂的 Python 代码
# 以下是 exec 的语法:
# exec(object, globals, locals)
# 参数
# obj -- 要执行的表达式。

#示例
# x = 10
# expr = """
# z = 30
# sum = x + y + z
# print(sum)
# """
# def func():
#     y = 20
#     exec(expr)
#     exec(expr, {'x': 1, 'y': 2})
#     exec(expr, {'x': 11, 'y': 222}, {'y': 33, 'z': 44})
#
# func()

#c. compile 将一个字符串编译为字节代码

# 语法：compile(source, filename, mode[, flags[, dont_inherit]])
# 参数：
# source -- 字符串或者AST（Abstract Syntax Trees）对象。。
# filename -- 代码文件名称，如果不是从文件读取代码则传递一些可辨认的值。
# mode -- 指定编译代码的种类。可以指定为 exec, eval, single。
# flags -- 变量作用域，局部命名空间，如果被提供，可以是任何映射对象。。
# flags和dont_inherit是用来控制编译源码时的标志

#2.2 输入输出相关
# input()输入
# s = input("请输入内容：")
# print(s)

# print()输出


#2.3 数据类型相关
# type(0)返回变量o的数据类型
# print(type("dsf"))

#2.4 内存相关
#id(o) o 是参数,返回一个变量的内存地址
# def func1():
#     print(2342)
# print(id(func1))

#hash(o) o是参数 返回一个可hash变量的哈希值,不可hash的值传入后会报错
# t = (1,2,3)
# l = [1,2,3]
# print(hash(t))
# print(hash(l))

# 文件操作相关
# open() 打开一个文件，返回一个文件操作符(文件句柄)
#操作文件的模式有r,w,a,r+,w+,a+ 共6种，每一种方式都可以用二进制的形式操作(rb,wb,ab,rb+,wb+,ab+)
# file = open("hosts.txt",'w')

# 模块操作相关
# __import__() 函数用于动态加载类和函数 。
# 如果一个模块经常变化就可以使用 __import__() 来动态载入。

# import导入的是一个标准模块，而标准模块的概念是一个文件夹里面必须包含__init__.py文件。
# 它的作用更像是一种声明，且import模块进来之后，万一原本的模块有什么变化，可以通过reload()进行重新加载。
# __import__()作为一个函数，只能接受字符串参数，返回值可以直接用来操作，
# 通常在动态加载的时候用到这个函数，最常见的情景就是插件功能的支持。

# 示例
# os = __import__('os')
# print(os.path.abspath('.'))


# 和数字相关
# 1.数据类型相关
# bool
# 描述：测试一个对象是True, 还是False.bool 是 int 的子类。
# 语法：class bool([x])
# 参数：x -- 要进行转换的参数。
# print(issubclass(bool, int)) # bool 是 int 子类

#用途
# 参数如果缺省，则返回False>>> bool() #未传入参数
# 传入布尔类型时，按原值返回
# 传入字符串时，空字符串返回False，否则返回True
# 传入数值时，0值返回False，否则返回True
# 传入元组、列表、字典等对象时，元素个数为空返回False，否则返回True

# int
# 描述：int() 函数用于将一个字符串或数字转换为整型。
# x可能为字符串或数值，将x 转换为一个普通整数。如果参数是字符串，那么它可能包含符号和小数点。
# 如果超出了普通整数的表示范围，一个长整数被返回。
# 语法：int(x, base =10)
# print(int(12.12))
# print(int("12.12"))#不支持

# float
# 将一个字符串或整数转换为浮点数

# complex
# 创建一个复数
# 语法：class complex([real[, imag]])
# 参数：
# real -- int, long, float或字符串；
# imag -- int, long, float；

#示例
# print(complex(1,2))
# print(complex('1'),complex("1+2j"))

# 2.进制转换相关
# bin
#bin() 返回一个整数 int 或者长整数 long int 的二进制表示。将十进制转换为二进制
# 语法：bin(x)
# 参数：x -- int 或者 long int 数字
# print(bin(2))

# oct
# 描述：将十进制转换为八进制
# print(oct(8))

# hex
#描述：hex() 函数用于将10进制整数转换成16进制，以字符串形式表示
# print(hex(16))

# 3.数学运算
# abs
#描述：返回数字绝对值或复数的模
# print(abs(-6),abs(4+5j))

# divmod
#描述：divmod() 函数把除数和余数运算结果结合起来，返回一个包含商和余数的元组(a // b, a % b)。
# 语法：divmod(a, b)
# 参数：a: 数字--被除数
# b: 数字--除数

# print(divmod(11,3))

# min
# 描述：min() 方法返回给定参数的最小值，参数可以为序列。
# 语法：min( x, y, z, .... )
# 参数：
# x -- 数值表达式。
# print(min(1,2,3,abs(-2)))

# max
# 描述：方法返回给定参数的最大值，参数可以为序列。
# 语法：min( x, y, z, .... )
# 参数：
# x -- 数值表达式。
# print(max(1,3,2,3,min(5,6,3)))

# sum
# 描述：sum() 方法对系列进行求和计算。
# 语法：sum(iterable[, start])
# 参数：
# iterable -- 可迭代对象，如：列表、元组、集合。
# start -- 指定相加的参数，如果没有设置这个值，默认为0。
# print(sum(range(10),10))

# round
# 描述：round() 函数返回浮点数x的四舍五入值。
# 语法：round( x [, n]  )
# 参数：
# x -- 数值表达式。
# n --代表小数点后保留几位
# print(round(10.023,1),round(10.495,1))

# pow
# 描述：pow() 方法返回 xy（x的y次方） 的值。
# 函数是计算x的y次方，如果z在存在，则再对结果进行取模，其结果等效于pow(x,y) %z
# 语法：pow(x, y[, z])
# 参数：
# x -- 数值表达式。
# y -- 数值表达式。
# z -- 数值表达式
# print(pow(10,2),pow(6,2,5))

# 和数据结构相关
# 1.列表和元组相关
# list
#描述：list() 函数创建列表或者用于将元组转换为列表
# 语法：list( tup )
# 参数：tup -- 要转换为列表的元组。
# print(list(range(10)))


# tuple
# 元组 tuple() 函数将列表转换为元组
# 语法：tuple( iterable )
# 参数：iterable -- 要转换为元组的可迭代序列。
# print(tuple([0,1,2,3,4]))
# print(tuple(range(5)))

# 2.字符串相关
# str
# 描述：str() 函数将对象转化为适于人阅读的形式。将字符类型、数值类型等转换为字符串类型
# 语法：class str(object='')
# 参数：object -- 对象。
# print(str(100),str(list(range(10))),str({'baidu': 'baidu.com', 'google': 'google.com'}))

# format
# 基本语法是通过 {} 和 : 来代替以前的 % 。
# 使用format()来格式化字符串时，使用在字符串中使用{}作为占位符，占位符的内容将引用format()中的参数进行替换。可以是位置参数、命名参数或者兼而有之。
# print('{}:您{}购买的{}到了！请下楼取快递。'.format('快递小哥','淘宝','快递'))
# n_list=['马云','马化腾','麻子','小红','李彦宏','二狗子']
# for name in n_list:
#     print('{}：您淘宝购买的快递到了！请下楼取快递！'.format(name))

# bytes
# 描述：将一个字符串转换成字节类型
# print(bytes("apple",encoding='utf-8'),bytes([1,2,3,4]))

# bytearry
#bytearray() 方法返回一个新字节数组。这个数组里的元素是可变的，并且每个元素的值范围: 0 <= x < 256。
# print(bytearray([1,2,3,4])[1],bytearray('test',encoding='utf-8'))

# memoryview
# 描述：memoryview() 函数返回给定参数的内存查看对象(Momory view)。返回由给定实参创建的“内存视图”对象，
# Python 代码访问一个对象的内部数据，只要该对象支持缓冲区协议 而无需进行拷贝
# print(memoryview(bytearray("abcds",'utf-8'))[2])

# ord
#描述：查看某个ascii对应的十进制数
# print(ord('A'),ord("哈"))

# chr
# 描述：chr() 用一个范围在 range（256）内的（就是0～255）整数作参数，返回一个对应的字符
# print(chr(97),chr(65))

# ascii
# 描述：ascii() 函数返回任何对象（字符串，元组，列表等）的可读版本。
# print(ascii("你好！世界"))

# repr
#repr() 函数将对象转化为供解释器读取的形式。
# dict = {'runoob': 'runoob.com', 'google': 'google.com'}
# print(repr(dict))

# reversed
#reversed 函数返回一个反转的迭代器
# l = (1,2,23,213,5612,342,43)
# print(list(reversed(l)))

#slice()
# 语法：
# slice(stop)
# slice(start, stop[, step])
# a = [1,4,2,3,1]
# print(a[slice(0,5,2)],a[0:5:2])#等价于a[0:5:2]

# 数据集合
# dict
# set
# frozenset
#描述：frozenset() 返回一个冻结的集合，冻结后集合不能再添加或删除任何元素。

# len
# sorted
# enumerate
#描述：enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列，同时列出数据和数据下标，一般用在 for 循环当中。
# 返回一个可以枚举的对象，该对象的next()方法将返回一个元组。
#语法：enumerate(sequence, [start=0])
# seq = ['one', 'two', 'three']
# for i, element in enumerate(seq,2):
#     print (i, element)


# all
#描述：接受一个迭代器，如果迭代器(元组或列表)的所有元素都为真，
# 那么返回True，否则返回False，元素除了是 0、空、None、False 外都算 True

#注意：空元组、空列表返回值为True，这里要特别注意

# all([1,0,3,6])
# False
# all([1,9,3,6])
# True
# all(['a', 'b', '', 'd'])
# False
# all([]) #空列表为真
# True
# all(()) #空元组为真
# True

# any
#描述：接受一个迭代器，如果迭代器里有一个元素为真，
# 那么返回True，否则返回False，元素除了是 0、空、None、False 外都算 True


# zip
# 描述：zip() 函数用于将可迭代的对象作为参数，将对象中对应的元素打包成一个个元组，
# 然后返回由这些元组组成的对象，这样做的好处是节约了不少的内存。

# 创建一个聚合了来自每个可迭代对象中的元素的迭代器：
# x = [3,2,1]
# y = [4,5]
# print(list(zip(y,x)))

#搭配for循环，数字与字符串组合
# a = range(5)
# b = list('abcde')
# [str(y) + str(x) for x,y in zip(a,b)]
# ['a0', 'b1', 'c2', 'd3', 'e4']

# filter
# 描述：filter() 函数用于过滤序列，过滤掉不符合条件的元素，返回由符合条件元素组成的新列表。
# 该接收两个参数，第一个为函数，第二个为序列，序列的每个元素作为参数传递给函数进行判断，然后返回 True 或 False，最后将返回 True 的元素放到新列表中。
# 过滤器，构造一个序列，等价于：[ item for item in iterables if function(item)]
# 在函数中设定过滤条件，逐一循环迭代器中的元素，将返回值为True时的元素留下，形成一个filter类型数据。
# 语法：filter(function, iterable)
# 参数：
# function -- 判断函数。
# iterable -- 可迭代对象。

# print(filter(lambda x: x>10,[1,11,2,45,7,6,13]))


# def is_odd(n):
#     return n % 2 == 1
#
# print(list(filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])))

# map
# 描述：map() 会根据提供的函数对指定序列做映射。返回一个将 function 应用于 iterable 中每一项并输出其结果的迭代器
# 语法：map(function, iterable, ...)
# 参数：
# function -- 函数
# iterable -- 一个或多个序列

# 提供了两个列表，对相同位置的列表数据进行相加
# list(map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10]))
# [3, 7, 11, 15, 19]

# def square(x) :            # 计算平方数
#     return x ** 2
# list(map(square, [1,2,3,4,5]))   # 计算列表各个元素的平方
# [1, 4, 9, 16, 25]


#匿名函数
#匿名函数：为了解决那些功能很简单的需求而设计的一句话函数

#这段代码
# def calc(n):
#     return n**n
# print(calc(10))

# #换成匿名函数
# calc = lambda n:n**n
# print(calc(10))


# 本章小结
# 说学习内置函数，不如说整理自己的知识体系。其实整理这些内置函数的过程也是在整理自己的知识体系。
# 我们讲课的时候会归类：常用或者不常用，主要还是根据场景而言。
# 一个优秀的程序员就应该是在该用这个方法的时候信手拈来，把每一个内置的函数都用的恰到好处。
# 要想做到这一点，至少要先了解，才能在需要的时候想起，进而将它用在该用的地方。
# 但是在这里，我还是以自己的一点经验之谈，把几个平时工作中相对更常用的方法推荐一下，请务必重点掌握：
# 其他：input,print,type,hash,open,import,dir
# str类型代码执行：eval,exec
# 数字：bool,int,float,abs,divmod,min,max,sum,round,pow
# 序列——列表和元组相关的：list和tuple
# 序列——字符串相关的：str，bytes，repr
# 序列：reversed，slice
# 数据集合——字典和集合：dict，set，frozenset
# 数据集合：len，sorted，enumerate，zip，filter，map